/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2016 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

#include <osgEarthAnnotation/AnnotationUtils>
#include <osgEarth/MapNode>
#include <osgEarth/Registry>
#include <osgEarth/ShaderGenerator>
#include <osgEarth/ScreenSpaceLayout>
#include <osgEarth/NodeUtils>
#include <osgEarth/Lighting>
#include <osg/Depth>
#include <osgText/Text>
#include "ImageNode.h"

#define LC "[ImageNode] "

using namespace osgEarth;
using namespace osgEarth::Annotation;
using namespace osgEarth::Symbology;

/*
osg::Geometry* createQuad(double s,double t,double heading,double scale)
{
	// set up the geoset.
	osg::Geometry* geom = new osg::Geometry();
	geom->setUseVertexBufferObjects(true);

	float x0 = - scale*s / 2.0;
	float y0 = - scale*t / 2.0;

	osg::Vec3Array* verts = new osg::Vec3Array(4);
	(*verts)[0].set(x0,y0,0);
	(*verts)[1].set(x0 + s,y0,0);
	(*verts)[2].set(x0 + s,y0 + t,0);
	(*verts)[3].set(x0,y0 + t,0);

	if(heading != 0.0)
	{
		osg::Matrixd rot;
		rot.makeRotate(heading,0.0,0.0,1.0);
		for (unsigned int i = 0; i < 4; i++)
		{
			(*verts)[i] = rot * (*verts)[i];
		}
	}
	geom->setVertexArray(verts);

	osg::Vec4Array* colors = new osg::Vec4Array(1);
	(*colors)[0].set(0.0f,0.0f,1.0,1.0f);
	geom->setColorArray(colors);
	geom->setColorBinding(osg::Geometry::BIND_OVERALL);

	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,4));

	return geom;
}*/

ImageNode::ImageNode(MapNode* mapNode,const GeoPoint& position,osg::Image* image,double scale,double head):
GeoPositionNode(mapNode,position)
{
    if(image)
    {
        IconSymbol* icon = _style.getOrCreate<IconSymbol>();
        icon->setImage(image);
    }

    init(scale,head);
}

void ImageNode::init(double scale,double head)
{
	heading = head;
	this->scale = scale;
    osg::StateSet* ss = this->getOrCreateStateSet();

    ScreenSpaceLayout::activate(ss);
    
    // Disable lighting for place nodes by default
    ss->setDefine(OE_LIGHTING_DEFINE, osg::StateAttribute::OFF);

    osgEarth::clearChildren( getPositionAttitudeTransform() );

    _geode = new osg::Geode();

    IconSymbol* icon = _style.get<IconSymbol>();
    image = icon ? icon->getImage() : 0L;

    if ( icon && image )
    {
        // apply the image icon.
        imageGeom = AnnotationUtils::createImageGeometry( 
            image,                    // image
            osg::Vec2s(0,0),          // offset
            0,                        // tex image unit
            heading,scale);

        if ( imageGeom )
        {
            _geode->addDrawable( imageGeom );

            ScreenSpaceLayoutData* layout = new ScreenSpaceLayoutData();
            layout->setPriority(getPriority());
            imageGeom->setUserData(layout);
        }
    }

    // ensure depth testing always passes, and disable depth buffer writes.
    osg::StateSet* stateSet = _geode->getOrCreateStateSet();
    stateSet->setAttributeAndModes( new osg::Depth(osg::Depth::ALWAYS, 0, 1, false), 1 );

    applyStyle( _style );

    setLightingIfNotSet( false );

    getPositionAttitudeTransform()->addChild( _geode );

	//auto rect = createQuad(image->s(),image->t(),head,scale);
	//_geode->addDrawable(rect);
    
    // generate shaders:
    Registry::shaderGenerator().run(this,"osgEarth.TrackNode",Registry::stateSetCache() );
}

void ImageNode::setPriority(float value)
{
    GeoPositionNode::setPriority( value );
    updateLayoutData();
}

void ImageNode::setHeading(double head)
{
	if(!image || heading == head)
		return;

	heading = head;
	float s = Registry::instance()->getDevicePixelRatio() * scale * image->s();
	float t = Registry::instance()->getDevicePixelRatio() * scale * image->t();

	float x0 = - s / 2.0;
	float y0 = - t / 2.0;

	osg::Vec3Array* verts = new osg::Vec3Array(4);
	(*verts)[0].set(x0,y0,0);
	(*verts)[1].set(x0 + s,y0,0);
	(*verts)[2].set(x0 + s,y0 + t,0);
	(*verts)[3].set(x0,y0 + t,0);

	if(head != 0.0)
	{
		osg::Matrixd rot;
		rot.makeRotate(heading,0.0,0.0,1.0);
		for(unsigned int i = 0; i < 4; i++)
		{
			(*verts)[i] = rot * (*verts)[i];
		}
	}
	imageGeom->setVertexArray(verts);
}

void ImageNode::updateLayoutData()
{
    osg::ref_ptr<ScreenSpaceLayoutData> data = new ScreenSpaceLayoutData();
    data->setPriority(getPriority());

    // re-apply annotation drawable-level stuff as neccesary.
    for (unsigned i = 0; i<_geode->getNumDrawables(); ++i)
    {
        _geode->getDrawable(i)->setUserData(data.get());
    }
}
 